home *** CD-ROM | disk | FTP | other *** search
- /*
- * sys_beos.cpp - System dependent routines, BeOS implementation
- *
- * Basilisk II (C) 1997-2001 Christian Bauer
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
- #include <StorageKit.h>
- #include <InterfaceKit.h>
- #include <kernel/fs_info.h>
- #include <drivers/Drivers.h>
- #include <device/scsi.h>
-
- #include <unistd.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <fcntl.h>
-
- #include "sysdeps.h"
- #include "main.h"
- #include "macos_util.h"
- #include "prefs.h"
- #include "user_strings.h"
- #include "sys.h"
-
- #define DEBUG 0
- #include "debug.h"
-
-
- // File handles are pointers to these structures
- struct file_handle {
- file_handle *next; // Pointer to next file handle (must be first in struct!)
- const char *name; // File/device name (copied, for mount menu)
- int fd; // fd of file/device
- bool is_file; // Flag: plain file or /dev/something?
- bool read_only; // Copy of Sys_open() flag
- loff_t start_byte; // Size of file header (if any)
- loff_t file_size; // Size of file data (only valid if is_file is true)
- };
-
- // Linked list of file handles
- static file_handle *first_file_handle;
-
- // Temporary buffer for transfers from/to kernel space
- const int TMP_BUF_SIZE = 0x10000;
- static uint8 *tmp_buf;
-
- // For B_SCSI_PREVENT_ALLOW
- static const int32 PREVENT = 1;
- static const int32 ALLOW = 0;
-
-
- /*
- * Check if device is a mounted HFS volume, get mount name
- */
-
- static bool is_drive_mounted(const char *dev_name, char *mount_name)
- {
- int32 i = 0;
- dev_t d;
- fs_info info;
- while ((d = next_dev(&i)) >= 0) {
- fs_stat_dev(d, &info);
- if (strcmp(dev_name, info.device_name) == 0) {
- status_t err = -1;
- BPath mount;
- BDirectory dir;
- BEntry entry;
- node_ref node;
- node.device = info.dev;
- node.node = info.root;
- err = dir.SetTo(&node);
- if (!err)
- err = dir.GetEntry(&entry);
- if (!err)
- err = entry.GetPath(&mount);
- if (!err) {
- strcpy(mount_name, mount.Path());
- return true;
- }
- }
- }
- return false;
- }
-
-
- /*
- * Initialization
- */
-
- void SysInit(void)
- {
- first_file_handle = NULL;
-
- // Allocate temporary buffer
- tmp_buf = new uint8[TMP_BUF_SIZE];
- }
-
-
- /*
- * Deinitialization
- */
-
- void SysExit(void)
- {
- delete[] tmp_buf;
- }
-
-
- /*
- * Create menu of used volumes (for "mount" menu)
- */
-
- void SysCreateVolumeMenu(BMenu *menu, uint32 msg)
- {
- for (file_handle *fh=first_file_handle; fh; fh=fh->next)
- if (!SysIsFixedDisk(fh))
- menu->AddItem(new BMenuItem(fh->name, new BMessage(msg)));
- }
-
-
- /*
- * Mount volume given name from mount menu
- */
-
- void SysMountVolume(const char *name)
- {
- file_handle *fh;
- for (fh=first_file_handle; fh && strcmp(fh->name, name); fh=fh->next) ;
- if (fh)
- MountVolume(fh);
- }
-
-
- /*
- * This gets called when no "floppy" prefs items are found
- * It scans for available floppy drives and adds appropriate prefs items
- */
-
- void SysAddFloppyPrefs(void)
- {
- // Only one floppy drive under BeOS
- PrefsAddString("floppy", "/dev/disk/floppy/raw");
- }
-
-
- /*
- * This gets called when no "disk" prefs items are found
- * It scans for available HFS volumes and adds appropriate prefs items
- */
-
- void SysAddDiskPrefs(void)
- {
- // Let BeOS scan for HFS drives
- D(bug("Looking for Mac volumes...\n"));
- system("mountvolume -allhfs");
-
- // Add all HFS volumes
- int32 i = 0;
- dev_t d;
- fs_info info;
- while ((d = next_dev(&i)) >= 0) {
- fs_stat_dev(d, &info);
- status_t err = -1;
- BPath mount;
- if (!strcmp(info.fsh_name, "hfs")) {
- BDirectory dir;
- BEntry entry;
- node_ref node;
- node.device = info.dev;
- node.node = info.root;
- err = dir.SetTo(&node);
- if (!err)
- err = dir.GetEntry(&entry);
- if (!err)
- err = entry.GetPath(&mount);
- }
- if (!err)
- err = unmount(mount.Path());
- if (!err) {
- char dev_name[B_FILE_NAME_LENGTH];
- if (info.flags & B_FS_IS_READONLY) {
- dev_name[0] = '*';
- dev_name[1] = 0;
- } else
- dev_name[0] = 0;
- strcat(dev_name, info.device_name);
- PrefsAddString("disk", dev_name);
- }
- }
- }
-
-
- /*
- * This gets called when no "cdrom" prefs items are found
- * It scans for available CD-ROM drives and adds appropriate prefs items
- */
-
- // Scan directory for CD-ROM drives, add them to prefs
- static void scan_for_cdrom_drives(const char *directory)
- {
- // Set directory
- BDirectory dir;
- dir.SetTo(directory);
- if (dir.InitCheck() != B_NO_ERROR)
- return;
- dir.Rewind();
-
- // Scan each entry
- BEntry entry;
- while (dir.GetNextEntry(&entry) >= 0) {
-
- // Get path and ref for entry
- BPath path;
- if (entry.GetPath(&path) != B_NO_ERROR)
- continue;
- const char *name = path.Path();
- entry_ref e;
- if (entry.GetRef(&e) != B_NO_ERROR)
- continue;
-
- // Recursively enter subdirectories (except for floppy)
- if (entry.IsDirectory()) {
- if (!strcmp(e.name, "floppy"))
- continue;
- scan_for_cdrom_drives(name);
- } else {
-
- D(bug(" checking '%s'\n", name));
-
- // Ignore partitions
- if (strcmp(e.name, "raw"))
- continue;
-
- // Open device
- int fd = open(name, O_RDONLY);
- if (fd < 0)
- continue;
-
- // Get geometry and device type
- device_geometry g;
- if (ioctl(fd, B_GET_GEOMETRY, &g, sizeof(g)) < 0) {
- close(fd);
- continue;
- }
-
- // Insert to list if it is a CD drive
- if (g.device_type == B_CD)
- PrefsAddString("cdrom", name);
- close(fd);
- }
- }
- }
-
- void SysAddCDROMPrefs(void)
- {
- // Don't scan for drives if nocdrom option given
- if (PrefsFindBool("nocdrom"))
- return;
-
- // Look for CD-ROM drives and add prefs items
- D(bug("Looking for CD-ROM drives...\n"));
- scan_for_cdrom_drives("/dev/disk");
- }
-
-
- /*
- * Add default serial prefs (must be added, even if no ports present)
- */
-
- void SysAddSerialPrefs(void)
- {
- system_info info;
- get_system_info(&info);
- switch (info.platform_type) {
- case B_BEBOX_PLATFORM:
- case B_AT_CLONE_PLATFORM:
- PrefsAddString("seriala", "serial1");
- PrefsAddString("serialb", "serial2");
- break;
- case B_MAC_PLATFORM:
- PrefsAddString("seriala", "modem");
- PrefsAddString("serialb", "printer");
- break;
- default:
- PrefsAddString("seriala", "none");
- PrefsAddString("serialb", "none");
- break;
- }
- }
-
-
- /*
- * Open file/device, create new file handle (returns NULL on error)
- */
-
- void *Sys_open(const char *name, bool read_only)
- {
- static bool published_all = false;
- bool is_file = (strstr(name, "/dev/") != name);
-
- D(bug("Sys_open(%s, %s)\n", name, read_only ? "read-only" : "read/write"));
-
- // Print warning message and eventually unmount drive when this is an HFS volume mounted under BeOS (double mounting will corrupt the volume)
- char mount_name[B_FILE_NAME_LENGTH];
- if (!is_file && !read_only && is_drive_mounted(name, mount_name)) {
- char str[256 + B_FILE_NAME_LENGTH];
- sprintf(str, GetString(STR_VOLUME_IS_MOUNTED_WARN), mount_name);
- WarningAlert(str);
- if (unmount(mount_name) != 0) {
- sprintf(str, GetString(STR_CANNOT_UNMOUNT_WARN), mount_name);
- WarningAlert(str);
- return NULL;
- }
- }
-
- int fd = open(name, read_only ? O_RDONLY : O_RDWR);
- if (fd < 0 && !published_all) {
- // Open failed, create all device nodes and try again, but only the first time
- system("mountvolume -publishall");
- published_all = true;
- fd = open(name, read_only ? O_RDONLY : O_RDWR);
- }
- if (fd >= 0) {
- file_handle *fh = new file_handle;
- fh->name = strdup(name);
- fh->fd = fd;
- fh->is_file = is_file;
- fh->read_only = read_only;
- fh->start_byte = 0;
- if (fh->is_file) {
- // Detect disk image file layout
- loff_t size = lseek(fd, 0, SEEK_END);
- uint8 data[256];
- lseek(fd, 0, SEEK_SET);
- read(fd, data, 256);
- FileDiskLayout(size, data, fh->start_byte, fh->file_size);
- }
-
- // Enqueue file handle
- fh->next = NULL;
- file_handle *q = first_file_handle;
- if (q) {
- while (q->next)
- q = q->next;
- q->next = fh;
- } else
- first_file_handle = fh;
- return fh;
- } else
- return NULL;
- }
-
-
- /*
- * Close file/device, delete file handle
- */
-
- void Sys_close(void *arg)
- {
- file_handle *fh = (file_handle *)arg;
- if (!fh)
- return;
-
- // Free device name and close file/device
- free((void *)fh->name);
- close(fh->fd);
-
- // Dequeue file handle
- file_handle *q = first_file_handle;
- if (q == fh) {
- first_file_handle = NULL;
- delete fh;
- return;
- }
- while (q) {
- if (q->next == fh) {
- q->next = fh->next;
- delete fh;
- return;
- }
- q = q->next;
- }
- }
-
-
- /*
- * Read "length" bytes from file/device, starting at "offset", to "buffer",
- * returns number of bytes read (or 0)
- */
-
- static inline ssize_t sread(int fd, void *buf, size_t count)
- {
- ssize_t res;
- while ((res = read(fd, buf, count)) == B_INTERRUPTED) ;
- return res;
- }
-
- size_t Sys_read(void *arg, void *buffer, loff_t offset, size_t length)
- {
- file_handle *fh = (file_handle *)arg;
- if (!fh)
- return 0;
-
- // D(bug("Sys_read(%08lx, %08lx, %Ld, %d)\n", fh, buffer, offset, length));
-
- // Seek to position
- if (lseek(fh->fd, offset + fh->start_byte, SEEK_SET) < 0)
- return 0;
-
- // Buffer in kernel space?
- size_t actual = 0;
- if ((uint32)buffer < 0x80000000) {
-
- // Yes, transfer via buffer
- while (length) {
- size_t transfer_size = (length > TMP_BUF_SIZE) ? TMP_BUF_SIZE : length;
- if (sread(fh->fd, tmp_buf, transfer_size) != transfer_size)
- return actual;
- memcpy(buffer, tmp_buf, transfer_size);
- buffer = (void *)((uint8 *)buffer + transfer_size);
- length -= transfer_size;
- actual += transfer_size;
- }
-
- } else {
-
- // No, transfer directly
- actual = sread(fh->fd, buffer, length);
- if (actual < 0)
- actual = 0;
- }
- return actual;
- }
-
-
- /*
- * Write "length" bytes from "buffer" to file/device, starting at "offset",
- * returns number of bytes written (or 0)
- */
-
- static inline ssize_t swrite(int fd, void *buf, size_t count)
- {
- ssize_t res;
- while ((res = write(fd, buf, count)) == B_INTERRUPTED) ;
- return res;
- }
-
- size_t Sys_write(void *arg, void *buffer, loff_t offset, size_t length)
- {
- file_handle *fh = (file_handle *)arg;
- if (!fh)
- return 0;
-
- // D(bug("Sys_write(%08lx, %08lx, %Ld, %d)\n", fh, buffer, offset, length));
-
- // Seek to position
- if (lseek(fh->fd, offset + fh->start_byte, SEEK_SET) < 0)
- return 0;
-
- // Buffer in kernel space?
- size_t actual = 0;
- if ((uint32)buffer < 0x80000000) {
-
- // Yes, transfer via buffer
- while (length) {
- size_t transfer_size = (length > TMP_BUF_SIZE) ? TMP_BUF_SIZE : length;
- memcpy(tmp_buf, buffer, transfer_size);
- if (swrite(fh->fd, tmp_buf, transfer_size) != transfer_size)
- return actual;
- buffer = (void *)((uint8 *)buffer + transfer_size);
- length -= transfer_size;
- actual += transfer_size;
- }
-
- } else {
-
- // No, transfer directly
- actual = swrite(fh->fd, buffer, length);
- if (actual < 0)
- actual = 0;
- }
- return actual;
- }
-
-
- /*
- * Return size of file/device (minus header)
- */
-
- loff_t SysGetFileSize(void *arg)
- {
- file_handle *fh = (file_handle *)arg;
- if (!fh)
- return true;
-
- if (fh->is_file)
- return fh->file_size;
- else {
- device_geometry g;
- if (ioctl(fh->fd, B_GET_GEOMETRY, &g, sizeof(g)) >= 0)
- return (loff_t)g.bytes_per_sector * g.sectors_per_track * g.cylinder_count * g.head_count;
- else
- return 0;
- }
- }
-
-
- /*
- * Eject volume (if applicable)
- */
-
- void SysEject(void *arg)
- {
- file_handle *fh = (file_handle *)arg;
- if (!fh)
- return;
-
- if (!fh->is_file)
- ioctl(fh->fd, B_EJECT_DEVICE);
- }
-
-
- /*
- * Format volume (if applicable)
- */
-
- bool SysFormat(void *arg)
- {
- file_handle *fh = (file_handle *)arg;
- if (!fh)
- return false;
-
- if (!fh->is_file)
- return ioctl(fh->fd, B_FORMAT_DEVICE) >= 0;
- else
- return false;
- }
-
-
- /*
- * Check if file/device is read-only (this includes the read-only flag on Sys_open())
- */
-
- bool SysIsReadOnly(void *arg)
- {
- file_handle *fh = (file_handle *)arg;
- if (!fh)
- return true;
-
- if (fh->is_file) {
-
- // File, return flag given to Sys_open
- return fh->read_only;
-
- } else {
-
- // Device, check write protection
- device_geometry g;
- if (ioctl(fh->fd, B_GET_GEOMETRY, &g, sizeof(g)) >= 0)
- return g.read_only | fh->read_only;
- else
- return fh->read_only; // Removable but not inserted
- }
- }
-
-
- /*
- * Check if the given file handle refers to a fixed or a removable disk
- */
-
- bool SysIsFixedDisk(void *arg)
- {
- file_handle *fh = (file_handle *)arg;
- if (!fh)
- return true;
-
- if (fh->is_file)
- return true;
- else {
- device_geometry g;
- if (ioctl(fh->fd, B_GET_GEOMETRY, &g, sizeof(g)) >= 0)
- return !g.removable;
- else
- return false; // Removable but not inserted
- }
- }
-
-
- /*
- * Check if a disk is inserted in the drive (always true for files)
- */
-
- bool SysIsDiskInserted(void *arg)
- {
- file_handle *fh = (file_handle *)arg;
- if (!fh)
- return false;
-
- if (fh->is_file)
- return true;
- else {
- status_t l;
- if (ioctl(fh->fd, B_GET_MEDIA_STATUS, &l, sizeof(l)) >= 0 && l == B_NO_ERROR)
- return true;
- else
- return false;
- }
- }
-
-
- /*
- * Prevent medium removal (if applicable)
- */
-
- void SysPreventRemoval(void *arg)
- {
- file_handle *fh = (file_handle *)arg;
- if (!fh)
- return;
-
- if (!fh->is_file)
- ioctl(fh->fd, B_SCSI_PREVENT_ALLOW, &PREVENT, sizeof(PREVENT));
- }
-
-
- /*
- * Allow medium removal (if applicable)
- */
-
- void SysAllowRemoval(void *arg)
- {
- file_handle *fh = (file_handle *)arg;
- if (!fh)
- return;
-
- if (!fh->is_file)
- ioctl(fh->fd, B_SCSI_PREVENT_ALLOW, &ALLOW, sizeof(ALLOW));
- }
-
-
- /*
- * Read CD-ROM TOC (binary MSF format, 804 bytes max.)
- */
-
- bool SysCDReadTOC(void *arg, uint8 *toc)
- {
- file_handle *fh = (file_handle *)arg;
- if (!fh)
- return false;
-
- if (!fh->is_file) {
- memset(tmp_buf, 0, 804);
- if (ioctl(fh->fd, B_SCSI_GET_TOC, tmp_buf, 804) < 0)
- return false;
- memcpy(toc, tmp_buf, 804);
- return true;
- } else
- return false;
- }
-
-
- /*
- * Read CD-ROM position data (Sub-Q Channel, 16 bytes, see SCSI standard)
- */
-
- bool SysCDGetPosition(void *arg, uint8 *pos)
- {
- file_handle *fh = (file_handle *)arg;
- if (!fh)
- return false;
-
- if (!fh->is_file) {
- if (ioctl(fh->fd, B_SCSI_GET_POSITION, tmp_buf, 16) < 0)
- return false;
- memcpy(pos, tmp_buf, 16);
- return true;
- } else
- return false;
- }
-
-
- /*
- * Play CD audio
- */
-
- bool SysCDPlay(void *arg, uint8 start_m, uint8 start_s, uint8 start_f, uint8 end_m, uint8 end_s, uint8 end_f)
- {
- file_handle *fh = (file_handle *)arg;
- if (!fh)
- return false;
-
- if (!fh->is_file) {
- scsi_play_position *p = (scsi_play_position *)tmp_buf;
- p->start_m = start_m;
- p->start_s = start_s;
- p->start_f = start_f;
- p->end_m = end_m;
- p->end_s = end_s;
- p->end_f = end_f;
- return ioctl(fh->fd, B_SCSI_PLAY_POSITION, p, sizeof(scsi_play_position)) == 0;
- } else
- return false;
- }
-
-
- /*
- * Pause CD audio
- */
-
- bool SysCDPause(void *arg)
- {
- file_handle *fh = (file_handle *)arg;
- if (!fh)
- return true;
-
- if (!fh->is_file)
- return ioctl(fh->fd, B_SCSI_PAUSE_AUDIO) == 0;
- else
- return false;
- }
-
-
- /*
- * Resume paused CD audio
- */
-
- bool SysCDResume(void *arg)
- {
- file_handle *fh = (file_handle *)arg;
- if (!fh)
- return false;
-
- if (!fh->is_file)
- return ioctl(fh->fd, B_SCSI_RESUME_AUDIO) == 0;
- else
- return false;
- }
-
-
- /*
- * Stop CD audio
- */
-
- bool SysCDStop(void *arg, uint8 lead_out_m, uint8 lead_out_s, uint8 lead_out_f)
- {
- file_handle *fh = (file_handle *)arg;
- if (!fh)
- return false;
-
- if (!fh->is_file)
- return ioctl(fh->fd, B_SCSI_STOP_AUDIO) == 0;
- else
- return false;
- }
-
-
- /*
- * Perform CD audio fast-forward/fast-reverse operation starting from specified address
- */
-
- bool SysCDScan(void *arg, uint8 start_m, uint8 start_s, uint8 start_f, bool reverse)
- {
- file_handle *fh = (file_handle *)arg;
- if (!fh)
- return false;
-
- if (!fh->is_file) {
- scsi_scan *p = (scsi_scan *)tmp_buf;
- p->speed = 0;
- p->direction = reverse ? -1 : 1;
- return ioctl(fh->fd, B_SCSI_SCAN, p, sizeof(scsi_scan)) == 0;
- } else
- return false;
- }
-
-
- /*
- * Set CD audio volume (0..255 each channel)
- */
-
- void SysCDSetVolume(void *arg, uint8 left, uint8 right)
- {
- file_handle *fh = (file_handle *)arg;
- if (!fh)
- return;
-
- if (!fh->is_file) {
- scsi_volume *p = (scsi_volume *)tmp_buf;
- p->flags = B_SCSI_PORT0_VOLUME | B_SCSI_PORT1_VOLUME;
- p->port0_volume = left;
- p->port1_volume = right;
- ioctl(fh->fd, B_SCSI_SET_VOLUME, p, sizeof(scsi_volume));
- }
- }
-
-
- /*
- * Get CD audio volume (0..255 each channel)
- */
-
- void SysCDGetVolume(void *arg, uint8 &left, uint8 &right)
- {
- file_handle *fh = (file_handle *)arg;
- if (!fh)
- return;
-
- left = right = 0;
- if (!fh->is_file) {
- scsi_volume *p = (scsi_volume *)tmp_buf;
- p->flags = B_SCSI_PORT0_VOLUME | B_SCSI_PORT1_VOLUME;
- if (ioctl(fh->fd, B_SCSI_GET_VOLUME, p, sizeof(scsi_volume)) == 0) {
- left = p->port0_volume;
- right = p->port1_volume;
- }
- }
- }
-